import XEUtils from 'xe-utils';
import Sortable from 'sortablejs';
import { watch, ref, reactive, nextTick } from 'vue';
import TableUtils from '@/components/tables/cfg/table-utils'

export const useSortHandle = ({ props, tableRef, tableOptions, tableDataHandle }) => {

  const { tableNodeMap } = tableDataHandle

  const moveNodeInfo = reactive({
    startIndex: 0,
    validateMoved: false,
  });

  /**
   * 初始化排序
   */
  const initSortable = () => {
    const { value: gridRef } = tableRef;
    nextTick(() => {
      Sortable.create(gridRef.$el.querySelector('.body--wrapper>.vxe-table--body tbody'), {
        group: 'tree-row-draggable',
        handle: '.drag-cell',
        dataIdAttr: 'rowid',
        dragClass: 'drag-move-cell',
        ghostClass: 'drag-done-cell',
        // 禁用h5原生拖拽行为
        forceFallback: true,
        onStart: evt => {
          moveNodeInfo.startIndex = evt.oldIndex;
          moveNodeInfo.validateMoved = false;
        },
        onMove: evt => {
          moveNodeInfo.validateMoved = false;
          const tableData = tableOptions.data;
          const { dragged: moveEleItem, related: stopEleItem } = evt;
          const oldIndex = Array.prototype.indexOf.call(moveEleItem.parentNode.children, moveEleItem);
          const newIndex = Array.prototype.indexOf.call(moveEleItem.parentNode.children, stopEleItem);
          const moveRowItem = tableNodeMap[moveEleItem.getAttribute('rowid')];
          const stopRowItem = tableNodeMap[stopEleItem.getAttribute('rowid')];
          const stopPrevEleItem = stopEleItem.previousElementSibling;
          let stopPrevRowItem = null;
          if (stopPrevEleItem) {
            stopPrevRowItem = tableNodeMap[stopPrevEleItem.getAttribute('rowid')];
          }
          const stopNextEleItem = stopEleItem.nextElementSibling;
          const stopNextRowItem = tableNodeMap[stopNextEleItem.getAttribute('rowid')];
          // 判断拖动方向
          if (oldIndex > newIndex) {
            // 判断节点级别是否相同
            if (moveRowItem.level !== stopRowItem.level) {
              // 处理拖动时，先向下移动，再向上移动的情况
              if (stopPrevRowItem && stopRowItem.parentId === stopPrevRowItem.parentId) {
                TableUtils.openMessage('只能在同级节点之间进行拖拽排序！');
                moveNodeInfo.validateMoved = true;
                return false;
              } else {
                if (stopRowItem.parentId === stopNextRowItem.parentId) {
                  TableUtils.openMessage('只能在同级节点之间进行拖拽排序！');
                  moveNodeInfo.validateMoved = true;
                  return false;
                }
              }
              TableUtils.openMessage('只能在同级节点之间进行拖拽排序！');
              return false;
            } else {
              // 如果节点级别相同，判断是否属于同一父节点
              if (moveRowItem.parentId !== stopRowItem.parentId) {
                TableUtils.openMessage('只能在同级节点之间进行拖拽排序！');
                return false;
              }
              if (
                stopPrevRowItem &&
                stopRowItem.level !== stopPrevRowItem.level &&
                XEUtils.findTree(moveRowItem.children, item => item.id === stopPrevRowItem.id)
              ) {
                TableUtils.openMessage('只能在同级节点之间进行拖拽排序！');
                moveNodeInfo.validateMoved = true;
                return false;
              }
            }
          } else if (oldIndex < newIndex) {
            // 判断节点级别是否相同
            if (moveRowItem.level !== stopRowItem.level) {
              // 如果节点级别不同，判断移动节点是否为展开状态
              if (gridRef.isTreeExpandByRow(moveRowItem)) {
                /**
                 * 判断停靠节点不能为移动节点的最后一个子元素
                 *
                 * 案例：
                 * 1. xxx
                 *  1.1 xxx
                 *    1.1.1 xxx
                 *    1.1.2 xxx
                 *  1.2 xxx
                 *    1.2.1 xxx
                 *    1.2.2 xxx
                 * 2. xxx
                 *  2.1 xxx
                 *  2.2 xxx
                 *
                 * 如果将【1.1 xxx】拖动到【1.1.2 xxx】下方时是不允许的
                 */
                if (XEUtils.findTree(moveRowItem.children, item => item.id === stopRowItem.id)) {
                  TableUtils.openMessage('只能在同级节点之间进行拖拽排序！');
                  return false;
                }
              }
              // 如果节点级别不同，判断停靠节点的下一个节点是否与移动节点处于同一级别
              const lastRowItem = tableData.slice(-1)[0];
              // 如果停靠节点是最后一个节点
              if (stopRowItem.id !== lastRowItem.id) {
                /**
                 * 停靠节点与下一个节点是否同处于一个父级
                 *
                 * 结构
                 * 1. xxx
                 *  1.1 xxx
                 *    1.1.1 xxx
                 *  1.2 xxx
                 *    1.2.1 xxx
                 *    1.2.2 xxx
                 *    1.2.3 xxx
                 * 2. xxx
                 *  2.1 xxx
                 *  2.2 xxx
                 *
                 * 案例：
                 *  将【1.1 xxx】拖动到【1.2.1 xxx】或【1.2.2 xxx】下方是不允许的
                 */
                if (stopNextRowItem.parentId === stopRowItem.parentId) {
                  TableUtils.openMessage('只能在同级节点之间进行拖拽排序！');
                  return false;
                }
                /**
                 * 判断停靠节点下一个节点是否与移动节处于同一级别
                 *
                 * 结构
                 * 1. xxx
                 *  1.1 xxx
                 *  1.2 xxx
                 *    1.2.1 xxx
                 *    1.2.2 xxx
                 * 2. xxx
                 *  2.1 xxx
                 *  2.2 xxx
                 *
                 * 案例：
                 *  如果将【1.1 xxx】拖动到【1.2.2 xxx】下方是允许的
                 */
                if (moveRowItem.parentId !== stopNextRowItem.parentId) {
                  /**
                   * 移动节点与停靠节点的上一级节点是否处于同一树节点下
                   *
                   * 结构：
                   * 1. xxx
                   *  1.1 xxx
                   *    1.1.1 xxx
                   *    1.1.2 xxx
                   *  1.2 xxx
                   *    1.2.1 xxx
                   *    1.2.2 xxx
                   * 2. xxx
                   *  2.1 xxx
                   *  2.2 xxx
                   *
                   * 案例：
                   *  如果将【1.1 xxx】拖动到【1.2.2 xxx】下方是允许的，
                   *  但是将【1.1 xxx】拖动到【2. xxx】下方是不允许的
                   */
                  if (stopRowItem.parentId !== stopPrevRowItem.parentId) {
                    TableUtils.openMessage('只能在同级节点之间进行拖拽排序！');
                    return false;
                  }
                }
              } else {
                // 判断移动节点是否为停靠节点的子级
                if (moveRowItem.parentId !== stopRowItem.id) {
                  TableUtils.openMessage('只能在同级节点之间进行拖拽排序！');
                  return false;
                }
              }
            } else {
              // 如果节点级别相同，停靠节点为树节点并且为展开状态
              if (gridRef.isTreeExpandByRow(stopRowItem)) {
                // 判断移动节点是否为停靠节点的子级
                if (moveRowItem.parentId !== stopRowItem.id) {
                  TableUtils.openMessage('只能在同级节点之间进行拖拽排序！');
                  return false;
                }
              }
              // 如果节点级别相同，判断是否属于同一父节点
              if (moveRowItem.parentId !== stopRowItem.parentId) {
                TableUtils.openMessage('只能在同级节点之间进行拖拽排序！');
                return false;
              }
            }
          } else {
            console.info('你没有任何拖动!!!');
          }
          moveNodeInfo.validateMoved = true;
          return true;
        },
        onEnd: evt => {
          const { oldIndex, newIndex, item: doneEleItem } = evt;
          if (!moveNodeInfo.validateMoved) return;
          // 表格数据
          const tableData = tableOptions.data;
          // 移动节点的上一个节点
          const prevEleItem = doneEleItem.previousElementSibling;
          // 移动节点的下一个节点
          const nextEleItem = doneEleItem.nextElementSibling;
          // 父节点元素
          const parentEleItem = doneEleItem.parentNode;
          // 移动节点
          const doneNode = XEUtils.findTree(
            tableData,
            row => row.id === doneEleItem.getAttribute('rowid'),
          );
          const doneRowItem = doneNode.item;
          if (oldIndex > newIndex) {
            console.info('向上拖拽!!!');
            const nextNode = XEUtils.findTree(
              tableData,
              row => row.id === nextEleItem.getAttribute('rowid'),
            );
            doneNode.items.splice(doneNode.index, 1)[0];
            doneNode.items.splice(nextNode.index, 0, doneRowItem);
          } else if (oldIndex < newIndex) {
            console.info('向下拖拽!!!');
            // 结束节点的上一个节点
            const prevNode = XEUtils.findTree(
              tableData,
              row => row.id === prevEleItem.getAttribute('rowid'),
            );
            // 结束节点的上一个节点的父级
            const prevParentNode = XEUtils.findTree(
              tableData,
              row => row.id === prevNode.item.parentId,
            );
            // 如果不属于同一级别
            if (prevNode.item.level !== doneNode.item.level) {
              doneNode.items.splice(doneNode.index, 1)[0];
              doneNode.items.splice(prevParentNode.index, 0, doneRowItem);
            } else {
              doneNode.items.splice(doneNode.index, 1)[0];
              doneNode.items.splice(prevNode.index, 0, doneRowItem);
            }
            // 如果拖拽节点为树节点并且为展开状态，需要将其子节点dom元素移动位置，否则子节点不会随父节点移动
            if (gridRef.isTreeExpandByRow(doneRowItem)) {
              let targetEleItem = doneEleItem;
              while (oldIndex < parentEleItem.children.length) {
                const newEleItem = parentEleItem.children[oldIndex];
                const siblingRowItem = doneNode.items.some(item => {
                  return item.id === newEleItem.getAttribute('rowid');
                });
                if (siblingRowItem) {
                  break;
                }
                insertElementAfter(newEleItem, targetEleItem);
                targetEleItem = newEleItem;
              }
            }
          } else {
            console.info('未做拖拽!!!');
          }
          tableOptions.data = [...tableData];
        },
      });
    });
  };

  /**
   * 添加元素到指定元素后面
   * @param {Element} newElement 新增的元素
   * @param {Element} targetElement 目标元素
   */
  const insertElementAfter = (newElement, targetElement) => {
    const parentElement = targetElement.parentNode;
    if (parentElement.lastChild === targetElement) {
      parentElement.appendChild(newElement);
    } else {
      parentElement.insertBefore(newElement, targetElement.nextSibling);
    }
  };

  return {
    initSortable
  }
}